package com.benyi.byiee.util;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream; 
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

import org.mozilla.universalchardet.UniversalDetector;

import jakarta.servlet.http.HttpServletResponse;

public class HttpFileUtil {
	
	public static String DEFAULT_CODE = "GBK";
	
	public static void writeImage(HttpServletResponse res, String file) throws IOException{
		byte []image = readFile(new File(file));
		OutputStream out=res.getOutputStream();
		int index=file.lastIndexOf(".");
		String type="image/"+file.substring(index+1); 
		res.setHeader("Content-Type", type); 
		out.write(image);
		out.flush();
	}
	
	public static void download(HttpServletResponse res, String file) throws IOException{
		File f = new File(file);
		byte []content = readFile(f);
		OutputStream out=res.getOutputStream(); 
		String name=f.getName();
		res.setContentType("application/octet-stream;charset=ISO8859-1");  
        res.setHeader("Content-Disposition","attachment;filename=\"" + encodeFilename(name) + "\"");  
        res.setHeader("Content-Length", String.valueOf(content.length)); 
        out.write(content);
		out.flush();
	} 
	
	private static void writeBytes(HttpServletResponse res, String ext, byte[] content) throws IOException{
		 
		OutputStream out=res.getOutputStream();   
		String type = getContentType(ext,false);   
		System.out.println("--ContentType:"+type+",ext:"+ext);
		res.setContentType(type); 
        res.setHeader("Content-Length", String.valueOf(content.length)); 
        out.write(content);
		out.flush();
	}
	
 
	public static  String encodeFilename(String fileName) {
    	//更安全的文件名编码（RFC 5987）
    	return URLEncoder.encode(fileName, StandardCharsets.UTF_8)
                .replaceAll("\\+", "%20");
    }
    
	public static byte[] readFile(File f) throws IOException {

		ByteArrayOutputStream bo = new ByteArrayOutputStream(1024*16);
		BufferedInputStream bi = new BufferedInputStream(new FileInputStream(f));
		byte []buf = new byte[1024*16];
		int len = bi.read(buf);
		while (len != -1) {
			bo.write(buf,0,len);
			len = bi.read(buf);
		}
		bi.close();
		bo.close();
		return bo.toByteArray(); 
	}
	
	private static String detectEncodingByBOM(byte[] bom) {
		int read = bom.length; 
		if (read >= 3 && bom[0] == (byte) 0xEF && bom[1] == (byte) 0xBB && bom[2] == (byte) 0xBF) {
			return "UTF-8";
		} else if (read >= 2 && bom[0] == (byte) 0xFE && bom[1] == (byte) 0xFF) {
			return "UTF-16BE";
		} else if (read >= 2 && bom[0] == (byte) 0xFF && bom[1] == (byte) 0xFE) {
			return "UTF-16LE";
		} else {
			return null; // 无 BOM 标记
		} 
	}
	
	private static String detectEncoding(byte[] buf) {
		UniversalDetector detector = new UniversalDetector(null);
		detector.handleData(buf, 0, buf.length);
		detector.dataEnd();
		String encoding = detector.getDetectedCharset();
		detector.reset();
		return encoding; 
	}
	
	public static String getCharCode(byte []buf,String []cname) {
		String code = detectEncodingByBOM(buf);
		if(code == null) {
			code = detectEncoding(buf); //检测文本字符集
		}
		cname[0] = code;
		if(code == null) {
			return null;
		}
		if(code.startsWith("UTF") || code.startsWith("BIG5")) {
			return code;
		} 
		return DEFAULT_CODE ; 
	}
	
	public static void writeFile(HttpServletResponse res, File file) throws IOException{
	 
		byte []content = readFile(file);
		
		String []oc= {null};
		String charCode = getCharCode(content,oc); 
		 
		String name = file.getName();
		String ext="txt";
		int index =name.lastIndexOf(".");
		if(index > 0) {
			ext = name.substring(index+1);
		} 
		
		if(charCode == null) {
			System.out.println("--output file:"+file.getAbsolutePath()+",ext="+ext);			
			writeBytes(res,ext,content); //无法确定的，作为附件下载
			return;
		}  
		
		String type = getContentType(ext,true);  
		
		res.setCharacterEncoding(charCode);
		res.setContentType(type);
		
		String text = new String(content,charCode);  
		 
		PrintWriter out = res.getWriter();
		out.write(text); 
		out.flush();
	}
	
	public static String getContentType(String ext,boolean isText) {
		String type="html/text"; 
		if(ext == null || ext.length() == 0) {
			return "text/plain";
		}
		ext = ext.toLowerCase();
		if(ext.equalsIgnoreCase("js")) {
			return "application/javascript";
		}
		if(ext.startsWith("htm")) {
			return "text/html";
		}
		if(ext.equalsIgnoreCase("css")) {
			return "text/css";
		}
		if(isText) {
			return "text/plain";
		}
		
		for(int i=0;i<image_types.length;i++) {
			if(ext.equals(image_types[i][0])) {
				return image_types[i][1];
			}
		}
		for(int i=0;i<video_types.length;i++) {
			if(ext.equals(video_types[i][0])) {
				return video_types[i][1];
			}
		}
		for(int i=0;i<audio_types.length;i++) {
			if(ext.equals(audio_types[i][0])) {
				return audio_types[i][1];
			}
		}
		return null;
	}
	
	private static final String image_types[][]= {{"jpg","image/jpeg"},
			{"jpeg","image/jpeg"},{"png","image/png"},{"gif","image/gif"},
			{"webp","image/webp"},{"svg","image/svg+xml"},{"bmp","image/bmp"},
			{"ico","image/x-icon"}};
	
	private static final String video_types[][]= {{"mp4","video/mp4"},
			{"webm","video/webm"},{"ogv","video/ogg"},{"ogg","video/ogg"},
			{"mov","video/quicktime"},{"avi","video/x-msvideo"},
			{"mpg","video/mpeg"},{"mpeg","video/mpeg"},
			{"mpe","video/mpeg"},{"m2v","video/mpeg"}};
	 
	private static final String audio_types[][]= {{"mp3","audio/mpeg"},
			{"wav","audio/wav"},{"ogg","audio/ogg"},{"oga","audio/ogg"},
			{"acc","audio/aac"},{"flac","audio/flac"},{"mid","audio/midi"},
			{"midi","audio/midi"},
			{"rm","application/vnd.rn-realmedia"},
			{"rmvb","application/vnd.rn-realmedia-vbr"}};
	  
	public static void main(String []args) throws IOException{
		/*
		for(int i=0;i<10;i++) {
			String name="d:/logs/test"+i+".txt";
			File f = new File(name);
			if(f.exists()==false) {
				continue;
			}
			byte []buf = readFile(f);
			String []cname = {""};
			
			String code = getCharCode(buf,cname);
			 
			System.out.println("file="+name);
			System.out.println("CharCode="+code+"\t Original:"+cname[0]);
			
			if(code == null) {
				System.out.println("binary content!");
				continue;
			}
			String text = new String(buf,code);  
			System.out.println(text);
			System.out.println();
		}
		*/
		String t = getContentType("flac",false);
		System.out.println(t);
	}
}
